/**
 * WorkflowInstance class for managing instantiated workflows with applied parameters
 */

import type {
  ComfyUIWorkflow,
  ParameterValues,
  VariableSyntax
} from '../types';
import type { WorkflowTemplate } from './WorkflowTemplate';
import { parseTemplate } from '../utils/template-parser';

/**
 * Represents an instantiated workflow with parameters applied
 */
export class WorkflowInstance {
  private readonly _template: WorkflowTemplate;
  private readonly _parameters: ParameterValues;
  private readonly _workflow: ComfyUIWorkflow;
  private readonly _instanceId: string;

  /**
   * Creates a new WorkflowInstance
   * @param template - The source template
   * @param parameters - Parameter values to apply
   */
  constructor(template: WorkflowTemplate, parameters: ParameterValues) {
    this._template = template;

    // Merge with default values
    const defaultValues = template.getDefaultValues();
    this._parameters = { ...defaultValues, ...parameters };

    this._instanceId = this.generateInstanceId();

    // Apply parameters to workflow
    this._workflow = this.applyParameters();
  }

  /**
   * Gets the source template
   */
  get template(): WorkflowTemplate {
    return this._template;
  }

  /**
   * Gets the applied parameters
   */
  get parameters(): ParameterValues {
    return { ...this._parameters };
  }

  /**
   * Gets the instantiated workflow with parameters applied
   */
  get workflow(): ComfyUIWorkflow {
    return JSON.parse(JSON.stringify(this._workflow)) as ComfyUIWorkflow;
  }

  /**
   * Gets the unique instance ID
   */
  get instanceId(): string {
    return this._instanceId;
  }

  /**
   * Gets the template ID
   */
  get templateId(): string {
    return this._template.id;
  }

  /**
   * Gets the template name
   */
  get templateName(): string {
    return this._template.name;
  }

  /**
   * Gets a specific parameter value
   * @param parameterName - Name of the parameter
   * @returns Parameter value or undefined if not set
   */
  getParameter(parameterName: string): unknown {
    return this._parameters[parameterName];
  }

  /**
   * Checks if a parameter is set
   * @param parameterName - Name of the parameter
   * @returns True if parameter is set
   */
  hasParameter(parameterName: string): boolean {
    return parameterName in this._parameters;
  }

  /**
   * Creates a new instance with updated parameters
   * @param newParameters - Parameters to update
   * @returns New WorkflowInstance with updated parameters
   */
  withParameters(newParameters: Partial<ParameterValues>): WorkflowInstance {
    const mergedParameters = { ...this._parameters, ...newParameters };
    return new WorkflowInstance(this._template, mergedParameters);
  }

  /**
   * Creates a new instance with a single parameter updated
   * @param parameterName - Name of the parameter to update
   * @param value - New parameter value
   * @returns New WorkflowInstance with updated parameter
   */
  withParameter(parameterName: string, value: unknown): WorkflowInstance {
    return this.withParameters({ [parameterName]: value });
  }

  /**
   * Converts the instance to a JSON-serializable object
   * @returns Object containing template ID, parameters, and workflow
   */
  toJSON(): {
    templateId: string;
    instanceId: string;
    parameters: ParameterValues;
    workflow: ComfyUIWorkflow;
  } {
    return {
      templateId: this.templateId,
      instanceId: this.instanceId,
      parameters: this.parameters,
      workflow: this.workflow
    };
  }

  /**
   * Gets the workflow ready for ComfyUI execution
   * @returns Workflow object ready for API submission
   */
  getExecutableWorkflow(): ComfyUIWorkflow {
    return this.workflow;
  }

  /**
   * Applies parameters to the template workflow
   * @private
   * @returns Workflow with parameters applied
   */
  private applyParameters(): ComfyUIWorkflow {
    const templateWorkflow = this._template.workflow;
    const workflowString = JSON.stringify(templateWorkflow);
    
    // Apply parameters using template parser
    const processedWorkflow = parseTemplate(workflowString, this._parameters, {
      supportedSyntax: ['{{}}', '${}', '@{}'] as VariableSyntax[],
      strictMode: true
    });

    try {
      return JSON.parse(processedWorkflow) as ComfyUIWorkflow;
    } catch (error) {
      throw new Error(`Failed to parse processed workflow: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  /**
   * Generates a unique instance ID
   * @private
   * @returns Unique instance ID
   */
  private generateInstanceId(): string {
    const timestamp = Date.now().toString(36);
    const random = Math.random().toString(36).substring(2, 8);
    return `${this._template.id}_${timestamp}_${random}`;
  }


}
